package com.qianfeng.smsplatform.strategy.filters.impl;

//
//                            _ooOoo_  
//                           o8888888o  
//                           88" . "88  
//                           (| -_- |)  
//                            O\ = /O  
//                        ____/`---'\____  
//                      .   ' \\| |// `.  
//                       / \\||| : |||// \  
//                     / _||||| -:- |||||- \  
//                       | | \\\ - /// | |  
//                     | \_| ''\---/'' | |  
//                      \ .-\__ `-` ___/-. /  
//                   ___`. .' /--.--\ `. . __  
//                ."" '< `.___\_<|>_/___.' >'"".  
//               | | : `- \`.;`\ _ /`;.`/ - ` : | |  
//                 \ \ `-. \_ __\ /__ _/ .-` / /  
//         ======`-.____`-.___\_____/___.-`____.-'======  
//                            `=---='  
//  
//         .............................................  
//                  佛祖镇楼                  BUG辟易  
//          佛曰:  
//                  写字楼里写字间，写字间里程序员；  
//                  程序人员写程序，又拿程序换酒钱。  
//                  酒醒只在网上坐，酒醉还来网下眠；  
//                  酒醉酒醒日复日，网上网下年复年。  
//                  但愿老死电脑间，不愿鞠躬老板前；  
//                  奔驰宝马贵者趣，公交自行程序员。  
//                  别人笑我忒疯癫，我笑自己命太贱；  
//  


import com.qianfeng.smsplatform.common.constants.CacheConstants;
import com.qianfeng.smsplatform.common.constants.InterfaceExceptionDict;
import com.qianfeng.smsplatform.common.model.Standard_Submit;
import com.qianfeng.smsplatform.strategy.feign.CacheService;
import com.qianfeng.smsplatform.strategy.filters.FilterChian;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.Set;

/**
 * Created by jackiechan on 2021/7/26/20:36
 * 限流是这样的,每个客户对同一个手机号发送的短信数据是有限制的.防止出现短信轰炸骚扰的情况
 *
 * @Author jackiechan
 */
@Component
public class LimitFilter implements FilterChian {

    private CacheService cacheService;

    @Autowired
    public void setCacheService(CacheService cacheService) {
        this.cacheService = cacheService;
    }

    @Override
    public boolean dealSms(Standard_Submit standard_submit) {
        System.err.println("限流的过滤器执行了");
        //即便是同一个手机号,不同的客户可以同时发送短信,限流是针对同一个客户对同一个手机号的限制
        //限制可能分很多种, 比如一分钟只能发几条, 五分钟能发几条, 一小时能发几条,一天能发几条等等,不同的限制,具体什么限制不清楚
        //第一个我们不知道是什么? 多少时间我们不知道, 多少条不知道
        //问题来了 什么都不知道 怎么做?
        //什么都不知道是因为我们没有数据,比如没有分别限制什么时间的数据, 没有每个时间分别限制多少的数据
        //是无论如何都没有数据?还是仅仅因为数据我们暂时没保存
        //假如说有个地方保存了我们的限流规则,我们直接去获取就可以了
        //限流的规则是怎么定义的 比如多少时间和多少次是如何定义出来的,或者是说如何绑定到一起的

        //上面的问题暂时好像没上面解决思路,那我们就假设上面的问题我们解决了,现在就要判断数量有没有超出限制
        //我们有一个限制的时间和条数
        //我们根据当前的时间 和限制时间为标准,向前推,找到对应的时间然后获取数量,再和限制的数量进行比较


        //我们获取到时间和数量两个值,那我们可不可以在redis中存放一下,比如我们以某个固定的key做为key,然后用hash保存?,小的field我们以限制的时间作为值,以score作为hashfield, ,同样 限制条数我们可以 value作为hashfield,具体值做为值

        //  score=60 value=1    score=300 value=2
        //很多个限流政策每个都是一个map(hash), 但是我们有很多个不同的条件,所以我们可以使用集合来保存所有的条件

        //因为限流需要根据数据来进行判断,并且还需要保持顺序, 所以我们使用后zset进行数据的存储
        //我们通过zset保存了所有的数据,其中分数代表我们的期望时间间隔,比如一分钟, 五分钟 半小时等
        //我们通过value来设置具体的次数,比如10次 20次等

        Integer clientID = standard_submit.getClientID();//当前发送者 客户
        String destMobile = standard_submit.getDestMobile();//目标手机号
        long currentTimeMillis = System.currentTimeMillis();//获取当前时间
        Set<Map> limitSet = cacheService.getDataFromZsetByIndex(CacheConstants.CACHE_LIMITSTRATEGY_KEY, 0, -1);
        for (Map map : limitSet) {
            //拿到了每一条限流策略
            System.err.println(map);

            Double time = (Double) map.get("score");//我们限制的时间
            Integer count = (Integer) map.get("value");//限制多少次

            //以当前时间为基准时间, 向前推我们当前遍历的时间,看看这个范围内有多少短信数据
            //我们必须每次发送短信都保存记录,要记录发送的时间
            //我们从什么地方用什么方式保存发送过的数据,我们用redis的zset来保存, 以手机号作为value,以发送时间作为分数进行保存
            //我们应该用一个key保存一下数据, key是什么? 我们发现这个限流是针对客户和手机号的,也就是不同的客户或者不同的手机号是想不影响
            //我们以当前的客户和手机号拼接出我们的key,然后以当前时间为结束,以向前推的时间为开始,去查询数据
            Long totalCount = cacheService.getSizeByScore(CacheConstants.CACHE_PREFIX_SMS_LIMIT + clientID + destMobile, currentTimeMillis - time * 1000, currentTimeMillis);
            //上面的totalcount代表的是当前时间范围内已经发送的短信的条数

            if (count <= totalCount) {
                //已经超出限制了
                System.err.println("超出了我们的限制次数time=====>"+time+"   --------->count"+count);
                standard_submit.setErrorCode(InterfaceExceptionDict.RETURN_STATUS_LIMIT_ERROR);
                standard_submit.setDescription("超出了限制次数,当前已经发送的此处是"+totalCount);
                return false;//返回false
            }
        }
        //当所有的限流措施都执行完了,就意味着我们没有被限制,应该添加一个数据
        //但是添加数据不能在这里添加,因为在这里添加万一后面的过滤器返回了fasle 就导致明明没有发送,却多了一条记录
        //此处我们先记录,做测试用
      //  cacheService.add2Zset(CacheConstants.CACHE_PREFIX_SMS_LIMIT + clientID + destMobile, currentTimeMillis+"", currentTimeMillis);
        return true;
    }
}
